package com.hong.utils.executors;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @Auther: Administrator
 * @Date: 2018/7/31 16:01
 * @Description:
 */
public class CompletableFutureExample4 {
    public static void main(String[] args) throws InterruptedException {
//        theAcceptBoth();
//        acceptEither();
//        runAfterBoth();
//        runAfterEither();
//        combine();
        compose();
        Thread.currentThread().join();
    }

    private static void compose() {
        /**
         * supplyAsync()返回一个新的CompletableFuture，通过运行在 ForkJoinPool.commonPool()中的任务与通过调用给定的供应商获得的值 异步完成。
         * thenCompose()返回一个新的CompletionStage，当这个阶段正常完成时，这个阶段将作为提供函数的参数执行。 请参阅CompletionStage文档，了解覆盖异常完成的规则。
         * thenAccept()返回一个新的CompletionStage，当此阶段正常完成时，将以该阶段的结果作为提供的操作的参数执行。 请参阅CompletionStage文档，了解覆盖异常完成的规则。
         */
        CompletableFuture.supplyAsync(()->{
            System.out.println("start the compose1");
            sleep(5);
            System.out.println("end the compose1");
            return "compost-1";
        }).thenCompose(s->CompletableFuture.supplyAsync(()->{
            System.out.println("start the compose2");
            sleep(3);
            System.out.println("end the compose2");
            return s.length();
        })).thenAccept(System.out::println);
    }

    private static void combine(){
        CompletableFuture.supplyAsync(()->{
            System.out.println("start the combine1");
            sleep(5);
            System.out.println("end the combine1");
            return "combine-1";
        }).thenCombine(CompletableFuture.supplyAsync(()->{
            System.out.println("start the combine2");
            sleep(3);
            System.out.println("end the combine2");
            return 100;
        }),(s,i)->s.length()>i).whenComplete((v,t)-> System.out.println(v));
    }

    private static  void acceptEither(){
        CompletableFuture.supplyAsync(()->{
            System.out.println("start the supplyAsync");
            sleep(5);
            System.out.println("end the supplyAsync");
            return "theAcceptBoth-1";
        }).acceptEither(CompletableFuture.supplyAsync(()->{
            System.out.println("start the acceptEdither2");
            sleep(3);
            System.out.println("end the acceptEdither2");
            return "acceptEither-2";
        }),System.out::println);
    }

    private static void runAfterBoth(){
        CompletableFuture.supplyAsync(()->{
            System.out.println("start the runAfterBoth");
            sleep(5);
            System.out.println("end the runAfterBoth");
            return "runAfterBoth-1";
        }).runAfterBothAsync(CompletableFuture.supplyAsync(()->{
            System.out.println("start the runAfterBoth");
            sleep(3);
            System.out.println("end the runAfterBoth");
            return 100;
        }),()-> System.out.println("DONE"));
    }

    private static void runAfterEither(){
        CompletableFuture.supplyAsync(()->{
            System.out.println("start the runAfterEither");
            sleep(5);
            System.out.println("end the runAfterEither");
            return "runAfterBoth-1";
        }).runAfterEither(CompletableFuture.supplyAsync(()->{
            System.out.println("start the runAfterEither2");
            sleep(3);
            System.out.println("end the runAfterEither2");
            return 100;
        }),()-> System.out.println("DONE"));
    }

    private static void theAcceptBoth(){
        CompletableFuture.supplyAsync(()->{
            System.out.println("start the supplyAsync");
            sleep(5);
            System.out.println("end the supplyAsync");
            return "theAcceptBoth";
        }).thenAcceptBoth(CompletableFuture.supplyAsync(()->{
            System.out.println("start the thenAcceptBoth");
            sleep(5);
            System.out.println("end the thenAcceptBoth");
            return 100;
        }),(s,i)-> System.out.println(s+"--"+i));
    }

    /**
     * sleep the specify seconds.
     * @param seconds
     */
    private static void sleep(long seconds){
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
